package com.googlecode.cannedbeans.generator.util;

import java.beans.PropertyDescriptor;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

public class AnnotationExtractorImpl implements AnnotationExtractor {

    Set < AnnotationFilter > annotationFilters = new HashSet < AnnotationFilter >();
    // The filtering should really be moved to another class, since the filtering logic isn't exactly a concern of this class.
    FilteringStrategy filteringStrategy = FilteringStrategy.UNANIMOUS;
    
    public Collection<Annotation> extractPropertyAnnotations(String name, Class<?> clazz) throws AnnotationExtractorException {
            try {
                    Set<Annotation> result = new HashSet<Annotation>();
                    Field field = clazz.getDeclaredField(name);
                    for (Annotation a : field.getAnnotations()){
                        if (this.doFilter(a)) {
                            result.add(a);
                        }
                    }			
                    PropertyDescriptor propdescriptor = new PropertyDescriptor(name, clazz);
                    Method getter = propdescriptor.getReadMethod();
                    for (Annotation a : getter.getAnnotations()){
                        if (this.doFilter(a)) {
                            result.add(a);
                        }
                    }	
                    Method setter = propdescriptor.getWriteMethod();
                    for (Annotation a : setter.getAnnotations()){
                        if (this.doFilter(a)) {
                            result.add(a);
                        }
                    }
                    return result;
            } catch (Exception e) {
                    throw new AnnotationExtractorException(e);
            }		
    }
    
    private boolean doFilter(Annotation annotation) {
        if (filteringStrategy == FilteringStrategy.SPLIT) {
            for (AnnotationFilter filter : this.annotationFilters) {
                if (filter.allow(annotation)) {
                    return true;
                }
                return false;
            }
        } else if (filteringStrategy == FilteringStrategy.UNANIMOUS) {
            for (AnnotationFilter filter : this.annotationFilters) {
                if (!filter.allow(annotation)) {
                    return false;
                }
                return true;
            }
        } else {
            throw new UnsupportedOperationException("Unsupported filtering strategy: " + filteringStrategy.name());
        }
        return false;
    }

    public void setAnnotationFilteringStrategy(FilteringStrategy strategy) {
        this.filteringStrategy = strategy;
    }

    public boolean addAnnotationFilter(AnnotationFilter filter) {
        return annotationFilters.add(filter);
    }

    public boolean removeAnnotationFilter(AnnotationFilter filter) {
        return annotationFilters.remove(filter);
    }

}
